package com.znyj.cloud.chain.tcphandler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.znyj.cloud.chain.util.ByteUtil;
import com.znyj.cloud.chain.util.CheckUtil;
import com.znyj.cloud.device.constant.SysConstant;
import com.znyj.cloud.device.pack.BasePackage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.apache.log4j.Logger;

import java.util.List;
import java.util.zip.CRC32;

/**
 * Created by gaoliwei02 on 17/8/7.
 */
public class ParseDecodeHandler extends ByteToMessageDecoder {
    private static final Logger logger = Logger.getLogger(ParseDecodeHandler.class);

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        BasePackage basePackage = decode(ctx, in);
        if (basePackage != null) {
            out.add(basePackage);
        }
    }

    //打印云使用的解码方式
    protected BasePackage decode(ChannelHandlerContext ctx, ByteBuf in) {
        int msgHead;
        int dataCrc;
        int version;
        int format;
        int reserved;
        int dataLength;
        byte[] payloadData = new byte[0];

        //可能出现TCP组包接收，至少能读包头
        in.markReaderIndex();
        if (in.readableBytes() < SysConstant.HEAD.HEAD_LENGTH && in.readableBytes() > 0) {
            //byte[] Data = new byte[24];
            //in.getBytes(24, Data);
            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.LESS_24_BYTE, "IP:" + ctx.channel().remoteAddress().toString(), in.readableBytes()));
            return null;
        } else if (in.readableBytes() == 0) {
            //logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.EQ_0_BYTE, "fire>>>*IP:" + ctx.channel().remoteAddress().toString(), 0));
            return null;
        }

        //读包头
        try {
            msgHead = ByteUtil.intTointBIG(in.readInt());
            dataCrc = ByteUtil.intTointBIG(in.readInt());
            version = ByteUtil.intTointBIG(in.readInt());
            format = ByteUtil.intTointBIG(in.readInt());
            reserved = ByteUtil.intTointBIG(in.readInt());
            dataLength = ByteUtil.intTointBIG(in.readInt());
        } catch (Exception e) {
            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.FIRST_ERROR, "fire IP:" + ctx.channel().remoteAddress().toString(), 0));
            ctx.fireChannelInactive();
            ctx.close();
            return null;
        }

        //头字段验证
        if (msgHead != SysConstant.HEAD.PROTOCOL_HEAD) {
            byte[] temp = new byte[4];
            temp[0] = in.getByte(3);
            temp[1] = in.getByte(2);
            temp[2] = in.getByte(1);
            temp[3] = in.getByte(0);
            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.HEAD_ERROR, "fire IP:" + ctx.channel().remoteAddress().toString() + " " + ByteUtil.assembleBytes2HexStr(temp), 0));
            ctx.fireChannelInactive();
            ctx.close();
            return null;
        }

        //读payload长度
        if (dataLength >= SysConstant.PAYLOAD_MAX_BYTE) {
            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.OVER_MAX_SIZE, "fire IP:" + ctx.channel().remoteAddress().toString(), 0));
            ctx.fireChannelInactive();
            ctx.close();
            return null;
        }
        //没有收够一个完整包（124 < 200)，等下一包返回NULL不需要下一个链条处理数据
        else if (in.readableBytes() < dataLength) {
            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.LESS_ONE_PAG, "IP:" + ctx.channel().remoteAddress().toString(), in.readableBytes()));
            in.resetReaderIndex();
            return null;
        }
        //收到大于一包数据，只取一包数据交给下一个链条处理
        else if (in.readableBytes() > dataLength) {
            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.MORE_ONE_PAG, "IP:" + ctx.channel().remoteAddress().toString(), in.readableBytes()));
            payloadData = new byte[dataLength];
        }
        //正好获取到一包数据
        else if (in.readableBytes() == dataLength) {
            payloadData = new byte[dataLength];
        }
        //其他不知名错误
        else {
            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.UNKNOWN, "fire IP:" + ctx.channel().remoteAddress().toString(), in.readableBytes()));
            ctx.fireChannelInactive();
            ctx.close();
            return null;
        }
        in.readBytes(payloadData);


        CRC32 crc32 = new CRC32();
        crc32.update(payloadData);
        int tempCRC = (int) crc32.getValue();
        crc32.reset();
        if (dataCrc != tempCRC) {
            //logger.error("dataCrc:" + dataCrc + " tempCRC:" + tempCRC +" ");
            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.CRC_ERROR, "fire IP:" + ctx.channel().remoteAddress().toString(), tempCRC));
            ctx.fireChannelInactive();
            ctx.close();
            return null;
        }
//        //检测版本是否正确
//        if (version == SysConstant.HEAD.VERSION_1) {
//
//        } else {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.VERSION_ERROR, "fire>>>*IP:" + ctx.channel().remoteAddress().toString(), version));
//            //logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " VERSION_ERROR fire");
//            ctx.fireChannelInactive();
//            ctx.close();
//            return null;
//        }

        //检测格式是否正确
        if (format == SysConstant.HEAD.FORMAT_BYTE) {

        } else if (format == SysConstant.HEAD.FORMAT_JSON) {

        } else {
            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.FORMAT_ERROR, "fire>>>*IP:" + ctx.channel().remoteAddress().toString(), format));
            ctx.fireChannelInactive();
            ctx.close();
            return null;
        }

        //开始组包
        BasePackage basePackage = new BasePackage();
        basePackage.setMsgHead(msgHead);
        basePackage.setDataCrc(dataCrc);
        basePackage.setVersion(version);
        basePackage.setFormat(format);
        basePackage.setDataLength(dataLength);
        basePackage.setPayloadData(payloadData);
        if (format == SysConstant.HEAD.FORMAT_JSON) {
            String jsonStr = ByteUtil.byte2String(payloadData);
            JSONObject payloadJson = new JSONObject();
            try {
                payloadJson = JSON.parseObject(jsonStr);
            } catch (Exception e) {
                logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.JSON_PARSE_ERROR, ">>>>IP:" + ctx.channel().remoteAddress().toString() + " json:" + jsonStr, 0));
                in.clear();
                return null;
            }
            basePackage.setJsonObject(payloadJson);
        }
        return basePackage;


    }


//        //头字段不相等clear
//        try {
//            msgHead = ByteUtil.intTointBIG(in.getInt(in.readerIndex()));
//            if (msgHead != SysConstant.HEAD.PROTOCOL_HEAD) {
//                byte[] temp = new byte[4];
//                temp[0] = in.getByte(3);
//                temp[1] = in.getByte(2);
//                temp[2] = in.getByte(1);
//                temp[3] = in.getByte(0);
//
//                logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.HEAD_ERROR, "cctx,head:0x" + ByteUtil.assembleBytes2HexStr(temp), 0));
//                logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " HEAD_NOTEQ");
//                //in.clear();
//                ctx.fireChannelInactive();
//                ctx.close();
//                return null;
//            }
//        }
//        //读头失败clear
//        catch (Exception e) {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.FIRST_ERROR, "length: " + in.readableBytes(), 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " READ_HEAD_ERROR");
//            in.clear();
//            ctx.fireChannelInactive();
//            ctx.close();
//            return null;
//        }
//
//
//        dataLength = ByteUtil.intTointBIG(in.getInt(in.readerIndex() + SysConstant.HEAD.HEAD_LENGTH_ADDR));
//        if (dataLength >= SysConstant.PAYLOAD_MAX_BYTE) {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.OVER_MAX_SIZE, "cctx,len:" + dataLength + ",ip:" + ctx.channel().remoteAddress().toString(), 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " OVER_MAX_SIZE");
//            in.clear();
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            return null;
//        }
//        //没有收够一个完整包（124 < 200)，等下一包返回NULL不需要下一个链条处理数据
//        else if (in.readableBytes() < dataLength) {
//            logger.info("dataLength:{} > readableBytes!" + dataLength + " " + in.readableBytes() + ctx.channel().remoteAddress().toString());
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " >");
//            return null;
//        }
//        //收到大于一包数据，只取一包数据交给下一个链条处理
//        else if (in.readableBytes() > dataLength) {
//            logger.info("dataLength:{} < readableBytes!" + dataLength + " " + in.readableBytes() + " " + ctx.channel().remoteAddress().toString());
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " <");
//            payloadData = new byte[dataLength];
//        }
//        //正好获取到一包数据
//        else if (in.readableBytes() == dataLength) {
//            payloadData = new byte[dataLength];
//        }
//        //其他不知名错误
//        else {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.UNKNOWN, "cctx,len:" + dataLength + ",readByte:" + in.readableBytes() + ",ip:" + ctx.channel().remoteAddress().toString(), 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " UNKNOWN");
//            in.clear();
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            return null;
//        }
//
//        //可以读那么多，放手去读
//        version = ByteUtil.intTointBIG(in.getInt(in.readerIndex())+ SysConstant.HEAD.HEAD_VERSION_ADDR);
//        format = ByteUtil.intTointBIG(in.getInt(in.readerIndex())+ SysConstant.HEAD.HEAD_FORMAT_ADDR);
//        reserved = ByteUtil.intTointBIG(in.getInt(in.readerIndex())+ SysConstant.HEAD.HEAD_RESERVED_ADDR);
//        dataCrc = ByteUtil.intTointBIG(in.getInt(in.readerIndex())+ SysConstant.HEAD.HEAD_CRC_ADDR);
//
//        //读完了
//        in.readBytes(SysConstant.HEAD.HEAD_LENGTH);
//        in.readBytes(payloadData);
//        CRC32 crc32 = new CRC32();
//        crc32.update(payloadData);
//        int tempCRC = (int) crc32.getValue();
//        crc32.reset();
//
//        //检测CRC是否正确
//        if (dataCrc != tempCRC) {
//            //logger.error("dataCrc:" + dataCrc + " tempCRC:" + tempCRC +" ");
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.CRC_ERROR, "cctx,dataCrc:" + dataCrc + " tempCRC:" + tempCRC, 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " CRC_ERROR");
//
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            return null;
//        }
//
//        //检测版本是否正确
//        if (version != SysConstant.HEAD.VERSION_1) {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.VERSION_ERROR, "version" + version, 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " VERSION_ERROR");
//
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            //return null;
//        }
//
//        //检测格式是否正确
//        if (format == SysConstant.HEAD.FORMAT_BYTE) {
//
//        } else if (format == SysConstant.HEAD.FORMAT_JSON) {
//
//        } else {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.FORMAT_ERROR, "version" + version, 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " FORMAT_ERROR");
//
//            in.clear();
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            return null;
//        }
//
//        //开始组包
//        ReceiveAndSendBasePackage receiveAndSendBasePackage = new ReceiveAndSendBasePackage();
//        receiveAndSendBasePackage.setMsgHead(msgHead);
//        receiveAndSendBasePackage.setDataCrc(dataCrc);
//        receiveAndSendBasePackage.setVersion(version);
//        receiveAndSendBasePackage.setFormat(format);
//        receiveAndSendBasePackage.setDataLength(dataLength);
//        receiveAndSendBasePackage.setPayloadData(payloadData);
//        if (format == SysConstant.HEAD.FORMAT_JSON) {
//            String jsonStr = ByteUtil.byte2String(payloadData);
//            JSONObject payloadJson = new JSONObject();
//            try {
//                payloadJson = JSON.parseObject(jsonStr);
//            } catch (Exception e) {
//                logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.JSON_PARSE_ERROR, "json:" + jsonStr, 0));
//                logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " JSON_PARSE_ERROR");
//                //ctx.fireChannelInactive();
//                //ctx.close();
//                return null;
//            }
//            receiveAndSendBasePackage.setJsonObject(payloadJson);
//        }
//        //logger.error("dataCrc:" + dataCrc + " tempCRC:" + tempCRC + " " + receiveAndSendBasePackage.getJsonObject().getString("ID"));
//        return receiveAndSendBasePackage;



//    //打印云使用的解码方式
//    protected ReceiveAndSendBasePackage decode(ChannelHandlerContext ctx, ByteBuf in) {
//        int msgHead;
//        int dataCrc;
//        int version;
//        int format;
//        int reserved;
//        int dataLength;
//        byte[] payloadData = new byte[0];
//
//        try {
//            msgHead = ByteUtil.intTointBIG(in.readInt());
//            dataCrc = ByteUtil.intTointBIG(in.readInt());
//            version = ByteUtil.intTointBIG(in.readInt());
//            format = ByteUtil.intTointBIG(in.readInt());
//            reserved = ByteUtil.intTointBIG(in.readInt());
//            dataLength = ByteUtil.intTointBIG(in.readInt());
//        } catch (Exception e) {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.FIRST_ERROR, "length: " + in.readableBytes(), 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " FIRST_ERROR");
//            in.clear();
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            return null;
//        }
//
//        //获取头字段
//        if (msgHead != SysConstant.HEAD.PROTOCOL_HEAD) {
//            byte[] temp = new byte[4];
//            temp[0] = in.getByte(3);
//            temp[1] = in.getByte(2);
//            temp[2] = in.getByte(1);
//            temp[3] = in.getByte(0);
//
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.HEAD_ERROR, "cctx,head:0x" + ByteUtil.assembleBytes2HexStr(temp), 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " HEAD_ERROR");
//            in.clear();
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            return null;
//        }
//
//        //检测版本是否正确
//        if (version == SysConstant.HEAD.VERSION_1) {
//
//        } else {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.VERSION_ERROR, "version" + version, 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " VERSION_ERROR");
//
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            //return null;
//        }
//
//        //检测格式是否正确
//        if (format == SysConstant.HEAD.FORMAT_BYTE) {
//
//        } else if (format == SysConstant.HEAD.FORMAT_JSON) {
//
//        } else {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.FORMAT_ERROR, "version" + version, 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " FORMAT_ERROR");
//
//            in.clear();
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            return null;
//        }
//
////        //超过接收最大长度
////        if (dataLength >= SysConstant.PAYLOAD_MAX_BYTE) {
////            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.OVER_MAX_SIZE, "cctx,len:" + dataLength + ",ip:" + ctx.channel().remoteAddress().toString(), 0));
////            ctx.fireChannelInactive();
////            ctx.close();
////            return null;
////        }
////        //没有收够一个完整包（124-24 < 200)，等下一包返回NULL不需要下一个链条处理数据
////        else if (in.readableBytes() - SysConstant.HEAD.HEAD_LENGTH < dataLength) {
////            logger.info("dataLength:{} > readableBytes!" + dataLength + " " + in.readableBytes() + ctx.channel().remoteAddress().toString());
////            return null;
////        }
////        //收到大于一包数据，只取一包数据交给下一个链条处理
////        else if (in.readableBytes() - SysConstant.HEAD.HEAD_LENGTH > dataLength) {
////            logger.info("dataLength:{} < readableBytes!" + dataLength + " " + in.readableBytes() + " " + ctx.channel().remoteAddress().toString());
////            payloadData = new byte[dataLength];
////        }
////        //正好获取到一包数据
////        else if (in.readableBytes() - SysConstant.HEAD.HEAD_LENGTH == dataLength) {
////            payloadData = new byte[dataLength];
////        }
////        //其他不知名错误
////        else {
////            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.UNKNOWN, "cctx,len:" + dataLength + ",readByte:" + in.readableBytes() + ",ip:" + ctx.channel().remoteAddress().toString(), 0));
////            ctx.fireChannelInactive();
////            ctx.close();
////            return null;
////        }
//        if (dataLength >= SysConstant.PAYLOAD_MAX_BYTE) {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.OVER_MAX_SIZE, "cctx,len:" + dataLength + ",ip:" + ctx.channel().remoteAddress().toString(), 0));
//            in.clear();
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            return null;
//        }
//        //没有收够一个完整包（124 < 200)，等下一包返回NULL不需要下一个链条处理数据
//        else if (in.readableBytes() < dataLength) {
//            logger.info("dataLength:{} > readableBytes!" + dataLength + " " + in.readableBytes() + ctx.channel().remoteAddress().toString());
//            return null;
//        }
//        //收到大于一包数据，只取一包数据交给下一个链条处理
//        else if (in.readableBytes() > dataLength) {
//            logger.info("dataLength:{} < readableBytes!" + dataLength + " " + in.readableBytes() + " " + ctx.channel().remoteAddress().toString());
//            payloadData = new byte[dataLength];
//        }
//        //正好获取到一包数据
//        else if (in.readableBytes() == dataLength) {
//            payloadData = new byte[dataLength];
//        }
//        //其他不知名错误
//        else {
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.UNKNOWN, "cctx,len:" + dataLength + ",readByte:" + in.readableBytes() + ",ip:" + ctx.channel().remoteAddress().toString(), 0));
//            in.clear();
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            return null;
//        }
//
//        in.readBytes(payloadData);
//
//
//        CRC32 crc32 = new CRC32();
//        crc32.update(payloadData);
//        int tempCRC = (int) crc32.getValue();
//        crc32.reset();
//
//        //int tempCRC = CRCUtil.makeCrc(payloadData);
//        if (dataCrc != tempCRC) {
//            //logger.error("dataCrc:" + dataCrc + " tempCRC:" + tempCRC +" ");
//            logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.CRC_ERROR, "cctx,dataCrc:" + dataCrc + " tempCRC:" + tempCRC, 0));
//            logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " CRC_ERROR");
//
//            in.clear();
//            //ctx.fireChannelInactive();
//            //ctx.close();
//            return null;
//        }
//
//        //开始组包
//        ReceiveAndSendBasePackage receiveAndSendBasePackage = new ReceiveAndSendBasePackage();
//        receiveAndSendBasePackage.setMsgHead(msgHead);
//        receiveAndSendBasePackage.setDataCrc(dataCrc);
//        receiveAndSendBasePackage.setVersion(version);
//        receiveAndSendBasePackage.setFormat(format);
//        receiveAndSendBasePackage.setDataLength(dataLength);
//        receiveAndSendBasePackage.setPayloadData(payloadData);
//        if (format == SysConstant.HEAD.FORMAT_JSON) {
//            String jsonStr = ByteUtil.byte2String(payloadData);
//            JSONObject payloadJson = new JSONObject();
//            try {
//                payloadJson = JSON.parseObject(jsonStr);
//            } catch (Exception e) {
//                logger.error(CheckUtil.monitorReport(SysConstant.ERROR_CODE.JSON_PARSE_ERROR, "json:" + jsonStr, 0));
//                logger.error(">>>>>>>>>>>>>>--------------IP:" + ctx.channel().remoteAddress().toString() + " DEVID:" + " JSON_PARSE_ERROR");
//
//                in.clear();
//                //ctx.fireChannelInactive();
//                //ctx.close();
//                return null;
//            }
//            receiveAndSendBasePackage.setJsonObject(payloadJson);
//        }
//        //logger.error("dataCrc:" + dataCrc + " tempCRC:" + tempCRC + " " + receiveAndSendBasePackage.getJsonObject().getString("ID"));
//        return receiveAndSendBasePackage;
//
//    }
}
